﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Ebt.Linq
{
	/// <summary>
	/// The base class for <see cref="IQueryProvider"/> implementations.
	/// </summary>
	public abstract class QueryProvider : IQueryProvider
	{
		#region IQueryProvider implementation
		IQueryable<S> IQueryProvider.CreateQuery<S>(Expression expression)
		{
			return new Query<S>(this, expression);
		}

		IQueryable IQueryProvider.CreateQuery(Expression expression)
		{
			Type elementType = TypeSystem.GetElementType(expression.Type);
			try
			{
				return (IQueryable) Activator.CreateInstance(typeof (Query<>).MakeGenericType(elementType), new object[] {this, expression});
			}
			catch (TargetInvocationException e)
			{
				throw e.InnerException;
			}
		}

		S IQueryProvider.Execute<S>(Expression expression)
		{
			return Execute<S>(expression);
		}

		object IQueryProvider.Execute(Expression expression)
		{
			return Execute(expression);
		}

		#endregion

		/// <summary>
		/// Gets text of the query that corresponds to the specified expression.
		/// </summary>
		/// <param name="expression">An expression.</param>
		/// <returns>Query string.</returns>
		public abstract string GetQueryText(Expression expression);

		/// <summary>
		/// Executes query.
		/// </summary>
		/// <param name="expression">An expression.</param>
		/// <returns>Query result.</returns>
		public abstract object Execute(Expression expression);

		/// <summary>
		/// Executes query.
		/// </summary>
		/// <param name="expression">An expression.</param>
		/// <returns>Query result.</returns>
		public abstract S Execute<S>(Expression expression);
	}
}
